/**
 * Project: HLA-OMNeT++: Omnet hla compliant version
 * File name: OmnetFederate.java
 * Description:  Initialize Omnet federate. This is actually an old version of the OmnetFederate and it will be soon updated
 *   
 * @author Emanuele Galli and Gaetano Cavarretta, Universita' di Roma Tor Vergata
 * @version v 1.0
 *   
 * @see The GNU Public License (GPL)
 */

/**    This file is part of HLA-OMNeT++.

    HLA-OMNeT++ is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    HLA-OMNeT++ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with HLA-OMNeT++.  If not, see <http://www.gnu.org/licenses/>.
*/

package federateOmnet;

import java.io.IOException;
//import java.net.Socket;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;

import org.portico.impl.hla1516.types.DoubleTime;
import org.portico.impl.hla1516.types.DoubleTimeInterval;

import hla.rti1516.AttributeHandle;
import hla.rti1516.AttributeHandleSet;
import hla.rti1516.AttributeHandleValueMap;
//import hla.rti1516.FederateNotExecutionMember;
import hla.rti1516.DeletePrivilegeNotHeld;
import hla.rti1516.FederateNotExecutionMember;
import hla.rti1516.FederationExecutionDoesNotExist;
import hla.rti1516.InteractionParameterNotDefined;
import hla.rti1516.InvalidInteractionClassHandle;
import hla.rti1516.InvalidParameterHandle;
import hla.rti1516.LogicalTime;
import hla.rti1516.InteractionClassHandle;
import hla.rti1516.NameNotFound;
import hla.rti1516.ObjectClassHandle;
import hla.rti1516.ObjectClassNotDefined;
import hla.rti1516.ObjectClassNotPublished;
import hla.rti1516.ObjectInstanceHandle;
import hla.rti1516.ObjectInstanceNameInUse;
import hla.rti1516.ObjectInstanceNameNotReserved;
import hla.rti1516.ObjectInstanceNotKnown;
import hla.rti1516.OrderType;
import hla.rti1516.ParameterHandle;
import hla.rti1516.ParameterHandleValueMap;
import hla.rti1516.RTIambassador;
import hla.rti1516.RTIinternalError;
import hla.rti1516.ResignAction;
import hla.rti1516.RestoreInProgress;
import hla.rti1516.SaveInProgress;
//import hla.rti1516.RestoreInProgress;
//import hla.rti1516.SaveInProgress;
import hla.rti1516.SynchronizationPointLabelNotAnnounced;
import hla.rti1516.TransportationType;
import hla.rti1516.jlc.NullFederateAmbassador;
import hla.rti1516.jlc.RtiFactoryFactory;

public class OmnetFederate extends NullFederateAmbassador {
	
	/* Ambassador */
	private RTIambassador rtiAmb = null;
	/* Interaction Handlee */
	private InteractionClassHandle ihMessageResponse = null;
	
	private InteractionClassHandle ihMessageJoinFederation = null;
	/* Publish Object Handle*/
	
    //private ObjectClassHandle handleObject = null;
	//private AttributeHandle attribHandle = null;
	private AttributeHandleSet attribHandleSet = null;
	/*  Subscribe Object Handle*/
	/*private ObjectClassHandle handleSub = null;
	private AttributeHandle attribHandleSub = null;
	private AttributeHandleSet attribHandleSetSub = null;
	*/
	//private ParameterHandleValueMap sendParamCollection = null;
	//private ParameterHandle paramHandle = null;
	
	//private ObjectInstanceHandle instanceHandle = null;
	//private AttributeHandleValueMap attribHandleMap = null;
	
	/* Federate name */
	private String fedName = "Omnet";
	/* Variabili di sincronizzazione */
	private double rawFederateTime;
	private double rawTimeForUpdate;
	private LogicalTime wrappedTimeForUpdate = null;
	    
	////////////////////////////////////////////
	////////Proprie dell'Ambasciatore///////////
	////////////////////////////////////////////
	private boolean timeConstrainedEnabled;
	private boolean timeRegulatingEnabled;
	private DoubleTime currentFederateTime;
	private DoubleTimeInterval federateLookAhead;
	private boolean syncronizedStart=false;
	private boolean syncronizedEnd=false;
	/* NEW VERSION
	public boolean startSyncPointAnnounced = false;
	public boolean endSyncPointAnnounced = false;
	public boolean startSyncPointAchieved = false;
	public boolean endSyncPointAchieved = false;
	*/
		
	private Start start;
	private InteractionClassHandle ihMessageRequest=null;
	private InteractionClassHandle ihMessageFailure=null;
	private InteractionClassHandle ihMessageRecovery=null;
	private InteractionClassHandle ihMessageBackground=null;
	private int backCount=1;
	private Hashtable <String,String>mappingInstanceToClass=new Hashtable<String,String>();
	private Hashtable <String,AttributeHandleValueMap>valueAttributeInstance=new Hashtable<String,AttributeHandleValueMap>();
	private ArrayList <String>updateFailureRecovery=new ArrayList<String>();
	
	public OmnetFederate(Start start){
		timeConstrainedEnabled = false;
	    timeRegulatingEnabled = false;
	    currentFederateTime = new DoubleTime(0);
	    federateLookAhead =  new DoubleTimeInterval(0.1); 
	    System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": inizialized");
	    this.start=start;
	    
	}
	
	/************************************************Getter Setter************************************************/
	public InteractionClassHandle getIhMessageJoinFederation() {
		return ihMessageJoinFederation;
	}
	public void setIhMessageJoinFederation(InteractionClassHandle ihMessageJoinFederation) {
		this.ihMessageJoinFederation = ihMessageJoinFederation;
	}
	public InteractionClassHandle getIhMessageResponse() {
		return ihMessageResponse;
	}
	public void setIhMessageResponse(InteractionClassHandle ihMessageResponse) {
		this.ihMessageResponse = ihMessageResponse;
	}
	public InteractionClassHandle getIhMessageBackground() {
		return ihMessageBackground;
	}
	public void setIhMessageBackground(InteractionClassHandle ihMessageBackground) {
		this.ihMessageBackground = ihMessageBackground;
	}
	public InteractionClassHandle getIhMessageFailure() {
		return ihMessageFailure;
	}
	public void setIhMessageFailure(InteractionClassHandle ihMessageFailure) {
		this.ihMessageFailure = ihMessageFailure;
	}
	public InteractionClassHandle getIhMessageRecovery() {
		return ihMessageRecovery;
	}
	public void setIhMessageRecovery(InteractionClassHandle ihMessageRecovery) {
		this.ihMessageRecovery = ihMessageRecovery;
	}
	public InteractionClassHandle getIhMessageRequest() {
		return ihMessageRequest;
	}
	public void setIhMessageRequest(InteractionClassHandle ihMessageRequest) {
		this.ihMessageRequest = ihMessageRequest;
	}
	public DoubleTime getCurrentFederateTime() {
		return currentFederateTime;
	}
	public void setCurrentFederateTime(DoubleTime currentFederateTime) {
		this.currentFederateTime = currentFederateTime;
	}
	public boolean isSyncronizedEnd() {
		return syncronizedEnd;
	}
	public void setSyncronizedEnd(boolean syncronizedEnd) {
		this.syncronizedEnd = syncronizedEnd;
	}
	public Hashtable getMappingInstanceToClass() {
		return mappingInstanceToClass;
	}
	public void setMappingInstanceToClass(Hashtable <String,String>mappingInstanceToClass) {
		this.mappingInstanceToClass = mappingInstanceToClass;
	}
	public ArrayList getUpdateFailureRecovery() {
		return updateFailureRecovery;
	}
	public void setUpdateFailureRecovery(ArrayList <String>updateFailureRecovery) {
		this.updateFailureRecovery = updateFailureRecovery;
	}
	/************************************************End Getter Setter************************************************/
	
	/************************************************Utility Function************************************************/
	public String createRequestServer(Object object) {
		
		if(object.getClass().getName().compareTo("federateOmnet.RequestToOmnet")==0){
			RequestToOmnet req=(RequestToOmnet)object;
			char ch='"';
			if(req.getId()==null)//BackgroundTraffic
				return("<msgBackgroundTraffic_"+(backCount++)+" source="+ch+req.getSource()+ch+" destination="+ch+req.getDestination()+ch+" payload="+ch+req.getPayload()+ch+" time="+ch+currentFederateTime.getTime()+ch+"/>\r\n\r\n");
			return("<msgComRequestFromRTI id="+ch+req.getId()+ch+" source="+ch+req.getSource()+ch+" destination="+ch+req.getDestination()+ch+" payload="+ch+req.getPayload()+ch+" protocol="+ch+"PROTOCOL"+ch+" time="+ch+currentFederateTime.getTime()+ch+"/>\r\n\r\n");
		}
		else if(object.getClass().getName().compareTo("federateOmnet.SendFailure")==0){
			SendFailure sendFl=(SendFailure)object;
			char ch='"';
			System.out.println(currentFederateTime.getTime()+" SendFailure>nome:"+sendFl.getIdNode());
			return ("<InfoMsg idNode="+ch+sendFl.getIdNode()+ch+" type="+ch+"0"+ch+" time="+ch+currentFederateTime.getTime()+ch+"/>\r\n\r\n");
		}
		else if(object.getClass().getName().compareTo("federateOmnet.SendRecovery")==0){
			SendRecovery sendRc=(SendRecovery)object;
			char ch='"';
			System.out.println(currentFederateTime.getTime()+" SendRecovery>nome:"+sendRc.getIdNode());
			return ("<InfoMsg idNode="+ch+sendRc.getIdNode()+ch+" type="+ch+"1"+ch+" time="+ch+currentFederateTime.getTime()+ch+"/>\r\n\r\n");
		}
		return null;
	}
	private SendRecovery createSendRecovery(ParameterHandleValueMap parameterValues, InteractionClassHandle interactionClass) {
		Iterator<ParameterHandle> i = parameterValues.keySet().iterator();
		ParameterHandle parameterHandle = null;
		SendRecovery sendRc=new SendRecovery();
		
		while(i.hasNext()){
			parameterHandle=(ParameterHandle) i.next();
			try {
				if(rtiAmb.getParameterName(interactionClass, parameterHandle).compareTo("idNode")==0){
					sendRc.setIdNode(new String((byte[])parameterValues.get(parameterHandle)));
					String istanceName=new String((byte[])parameterValues.get(parameterHandle));
					updateFailureRecovery.add((istanceName+":Recovery"));
				}
			} catch (NumberFormatException e) {
				e.printStackTrace();
				return null;
			} catch (InvalidInteractionClassHandle e) {
				e.printStackTrace();
				return null;
			} catch (InvalidParameterHandle e) {
				e.printStackTrace();
				return null;
			} catch (InteractionParameterNotDefined e) {
				e.printStackTrace();
				return null;
			} catch (FederateNotExecutionMember e) {
				e.printStackTrace();
				return null;
			} catch (RTIinternalError e) {
				e.printStackTrace();
				return null;
			}
		}
		return sendRc;
}

private SendFailure createSendFailure(ParameterHandleValueMap parameterValues, InteractionClassHandle interactionClass) {
	Iterator<ParameterHandle> i = parameterValues.keySet().iterator();
	ParameterHandle parameterHandle = null;
	SendFailure sendFl=new SendFailure();
	
	while(i.hasNext()){
		parameterHandle=(ParameterHandle) i.next();
		try {
			if(rtiAmb.getParameterName(interactionClass, parameterHandle).compareTo("idNode")==0){
				sendFl.setIdNode(new String((byte[])parameterValues.get(parameterHandle)));
				String istanceName=new String((byte[])parameterValues.get(parameterHandle));
				updateFailureRecovery.add((istanceName+":Failure"));
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
			return null;
		} catch (InvalidInteractionClassHandle e) {
			e.printStackTrace();
			return null;
		} catch (InvalidParameterHandle e) {
			e.printStackTrace();
			return null;
		} catch (InteractionParameterNotDefined e) {
			e.printStackTrace();
			return null;
		} catch (FederateNotExecutionMember e) {
			e.printStackTrace();
			return null;
		} catch (RTIinternalError e) {
			e.printStackTrace();
			return null;
		}
	}
return sendFl;
}
	
	private RequestToOmnet createRequestToOmnet(ParameterHandleValueMap parameterValues, InteractionClassHandle interactionClass) {
		RequestToOmnet request=new RequestToOmnet();
		Iterator<ParameterHandle> i = parameterValues.keySet().iterator();
		ParameterHandle parameterHandle=null;
		
		while(i.hasNext()){
			parameterHandle = (ParameterHandle) i.next();
			try {
				if(rtiAmb.getParameterName(interactionClass, parameterHandle).compareTo("source")==0)
					request.setSource(new String((byte[])parameterValues.get(parameterHandle)));
				else if(rtiAmb.getParameterName(interactionClass, parameterHandle).compareTo("destination")==0)
					request.setDestination(new String((byte[])parameterValues.get(parameterHandle)));
				else if(rtiAmb.getParameterName(interactionClass, parameterHandle).compareTo("payload")==0)
					request.setPayload(new String((byte[])parameterValues.get(parameterHandle)));
				else if(rtiAmb.getParameterName(interactionClass, parameterHandle).compareTo("id")==0)
					request.setId(new String((byte[])parameterValues.get(parameterHandle)));
			} catch (NumberFormatException e) {
				e.printStackTrace();
				return null;
			} catch (InvalidInteractionClassHandle e) {
				e.printStackTrace();
				return null;
			} catch (InvalidParameterHandle e) {
				e.printStackTrace();
				return null;
			} catch (InteractionParameterNotDefined e) {
				e.printStackTrace();
				return null;
			} catch (FederateNotExecutionMember e) {
				e.printStackTrace();
				return null;
			} catch (RTIinternalError e) {
				e.printStackTrace();
				return null;
			}
		}
		return request;		
	}
	
	private RequestToOmnet createBackgroundTraffic(ParameterHandleValueMap parameterValues, InteractionClassHandle interactionClass) {
		RequestToOmnet request=new RequestToOmnet();
		Iterator<ParameterHandle> i = parameterValues.keySet().iterator();
		ParameterHandle parameterHandle=null;
		
		while(i.hasNext()){
			parameterHandle = (ParameterHandle) i.next();
			try {
				if(rtiAmb.getParameterName(interactionClass, parameterHandle).compareTo("source")==0)
					request.setSource(new String((byte[])parameterValues.get(parameterHandle)));
				else if(rtiAmb.getParameterName(interactionClass, parameterHandle).compareTo("destination")==0)
					request.setDestination(new String((byte[])parameterValues.get(parameterHandle)));
				else if(rtiAmb.getParameterName(interactionClass, parameterHandle).compareTo("payload")==0)
					request.setPayload(new String((byte[])parameterValues.get(parameterHandle)));
				
			} catch (NumberFormatException e) {
				e.printStackTrace();
				return null;
			} catch (InvalidInteractionClassHandle e) {
				e.printStackTrace();
				return null;
			} catch (InvalidParameterHandle e) {
				e.printStackTrace();
				return null;
			} catch (InteractionParameterNotDefined e) {
				e.printStackTrace();
				return null;
			} catch (FederateNotExecutionMember e) {
				e.printStackTrace();
				return null;
			} catch (RTIinternalError e) {
				e.printStackTrace();
				return null;
			}
		}
		return request;		
	}
	/*********************************************End Utility Function*********************************************/
	
	/********************************RTI services through the ambassador*************************/
	
	public void getAmbassadors(){
		try{
			rtiAmb = RtiFactoryFactory.getRtiFactory().getRtiAmbassador();
			rtiAmb.initializeRTI(null);
					}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void joinFederation(String nameFederation){
		while(true){
			try {
				rtiAmb.joinFederationExecution(fedName, nameFederation, this, null);
			}
			catch (FederationExecutionDoesNotExist e) {
				continue;
			} 
			catch (Exception e) {
				e.printStackTrace();
				continue;
			}
			break;
		}
		System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": joins the federation");
	}
	
	public void isTimeConstrained(){
		try{
			// Enable time constrained
			rtiAmb.enableTimeConstrained();
			while(!timeConstrainedEnabled){
				rtiAmb.evokeMultipleCallbacks(0.1, 1.0);
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void isTimeRegulating(){
		try{
			// Enable time regulating
			rtiAmb.enableTimeRegulation(federateLookAhead);
			while(!timeRegulatingEnabled){
				rtiAmb.evokeMultipleCallbacks(0.1, 1.0);
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
	
	}
	
	public void getSynchronized(String label){
		while(true){
			try {
				rtiAmb.synchronizationPointAchieved(label);
				
				if(label.equals("StartTest")){
					System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": Request of synchronization");
					while(!this.syncronizedStart){
						
						rtiAmb.evokeMultipleCallbacks(0.1, 1.0);
					}
					
				}
				break;
			} catch (SynchronizationPointLabelNotAnnounced e) {
				e.printStackTrace();
				continue;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public void timeAdvanceAndCallback(){
		try{
			
			
			rawFederateTime = currentFederateTime.getTime();
			rawTimeForUpdate = rawFederateTime + federateLookAhead.getTime();
			wrappedTimeForUpdate = new DoubleTime(rawTimeForUpdate);
			// Request a time advancement
			
			rtiAmb.nextMessageRequest(wrappedTimeForUpdate);
			// Wait until the federate time has been updated
			while ( currentFederateTime.getTime() == rawFederateTime ){
				// NEW VERSION
				//if (endSyncPointAnnounced) { break; }
	        	rtiAmb.evokeMultipleCallbacks(0.1, 1.0);
	        }
			
	    }
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void getInteractionHandle(String value){
		try{
			
			/* Get Interaction Handle */
			if(value.compareTo("RequestToOmnet")==0)
				ihMessageRequest = rtiAmb.getInteractionClassHandle(value);
			else if(value.compareTo("ResponseToRepast")==0)
				ihMessageResponse = rtiAmb.getInteractionClassHandle(value);
			else if(value.compareTo("SendFailure")==0)
				ihMessageFailure = rtiAmb.getInteractionClassHandle(value);
			else if(value.compareTo("SendRecovery")==0)
				ihMessageRecovery = rtiAmb.getInteractionClassHandle(value);
			else if(value.compareTo("BackgroundTraffic")==0)
				ihMessageBackground = rtiAmb.getInteractionClassHandle(value);
			/* old fed sync*/
			else if(value.compareTo("JoinedOmnet")==0)
				ihMessageJoinFederation = rtiAmb.getInteractionClassHandle(value);
			/* */
			System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": gets interaction handle");
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	public void publishInteraction(InteractionClassHandle ihMessage){
		try{
			/* Publish Interaction */
			rtiAmb.publishInteractionClass(ihMessage);
			System.out.println("\t"+currentFederateTime.getTime() + " " + fedName + ": publishes interaction");
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	public void subscribeInteraction(InteractionClassHandle ihMessage){
		try{
			/* Subscribe Interaction*/
			rtiAmb.subscribeInteractionClass(ihMessage);
			System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": subscribe interaction");
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	public void sendMessage(Object response,InteractionClassHandle ihMessage){
		try {
					
			ParameterHandleValueMap sendParamCollection=null;
			ParameterHandle paramHandle=null;
			if(response.getClass().getName().equals("federateOmnet.ResponseToRepast")){
				
				sendParamCollection = rtiAmb.getParameterHandleValueMapFactory().create(1);
				byte[] msgSendByte;
				paramHandle = rtiAmb.getParameterHandle(ihMessage, "source");
				msgSendByte =((ResponseToRepast) response).getSource().getBytes();
				sendParamCollection.put(paramHandle, msgSendByte);
				
				paramHandle = rtiAmb.getParameterHandle(ihMessage, "destination");
				msgSendByte = ((ResponseToRepast)response).getDestination().getBytes();
				sendParamCollection.put(paramHandle, msgSendByte);
				
				paramHandle = rtiAmb.getParameterHandle(ihMessage, "status");
				msgSendByte = ((ResponseToRepast)response).getStatus().getBytes();
				sendParamCollection.put(paramHandle, msgSendByte);
				
				paramHandle = rtiAmb.getParameterHandle(ihMessage, "id");
				String id=""+((ResponseToRepast)response).getId();
				msgSendByte=id.getBytes();
				sendParamCollection.put(paramHandle, msgSendByte);
				
				byte[] tag = "ResponseToRepast".getBytes();
				rtiAmb.sendInteraction(ihMessage, sendParamCollection, tag);
			}
			/* old fed sync */
			else if(response.getClass().getName().equals("java.lang.Boolean")){
				sendParamCollection = rtiAmb.getParameterHandleValueMapFactory().create(1);
				paramHandle = rtiAmb.getParameterHandle(ihMessage, "joined");
				sendParamCollection.put(paramHandle, "true".getBytes());
				
				byte[] tag = "JoinedOmnet".getBytes();
				rtiAmb.sendInteraction(ihMessage, sendParamCollection, tag);
				System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": Send interaction JoinedOmnet");
			}
			/* */
				
						
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
	
	
	public void publishAndRegisterObject(String nameObject,String[] attributeName,String istanceName){
		try{
			int size=0;
			/* Pubblicazione dell'oggetto. Se l'oggetto e' stato pubblicato allora viena creata solo l'istanza*/
			if(!mappingInstanceToClass.containsValue(nameObject)){
				/* Ottiene l'handle per l'oggetto e l'attributo */
				ObjectClassHandle handleObject = rtiAmb.getObjectClassHandle(nameObject);
				attribHandleSet = rtiAmb.getAttributeHandleSetFactory().create();
				while(size<attributeName.length){
					AttributeHandle attribHandle = rtiAmb.getAttributeHandle(handleObject, attributeName[size]);
					attribHandleSet.add(attribHandle);
					size++;
				}
				rtiAmb.publishObjectClassAttributes(handleObject, attribHandleSet); 
				System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": Publish Object "+nameObject);
				
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void createInstance(String nameObject,String istanceName){
		/* Instance registration */
		try {
			/* Gets Object handle and registers the object  */
			ObjectClassHandle handleObject = rtiAmb.getObjectClassHandle(nameObject);
			rtiAmb.registerObjectInstance(handleObject, istanceName);
			mappingInstanceToClass.put(istanceName, nameObject);
			System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": Register Instance "+istanceName);
		} catch (ObjectClassNotDefined e) {
			e.printStackTrace();
		} catch (ObjectClassNotPublished e) {
			e.printStackTrace();
		} catch (ObjectInstanceNameNotReserved e) {
			e.printStackTrace();
		} catch (ObjectInstanceNameInUse e) {
			e.printStackTrace();
		} catch (FederateNotExecutionMember e) {
			e.printStackTrace();
		} catch (SaveInProgress e) {
			e.printStackTrace();
		} catch (RestoreInProgress e) {
			e.printStackTrace();
		} catch (RTIinternalError e) {
			e.printStackTrace();
		} catch (NameNotFound e) {
			e.printStackTrace();
		}
		
	
	}
	
	
	public void inizializeObjectAttribute(String nameObject,String[] attributeValue,String istanceName,String[] attributeName){
		try{
			rawFederateTime = currentFederateTime.getTime();
			rawTimeForUpdate = rawFederateTime + federateLookAhead.getTime();
			wrappedTimeForUpdate = new DoubleTime(rawTimeForUpdate);
			/* Attributes mapping  and update*/
			AttributeHandleValueMap attribHandleMap = rtiAmb.getAttributeHandleValueMapFactory().create(1);
			int size=0;
			ObjectClassHandle handleObject = rtiAmb.getObjectClassHandle(nameObject);
			ObjectInstanceHandle instanceHandle=rtiAmb.getObjectInstanceHandle(istanceName);
			
			while(size<attributeValue.length){
				byte[] attribValueByte = attributeValue[size].getBytes();
				AttributeHandle attribHandle=rtiAmb.getAttributeHandle(handleObject, attributeName[size]);
				
				attribHandleMap.put(attribHandle, attribValueByte);
				
				size++;
			}
			this.valueAttributeInstance.put(istanceName,attribHandleMap);
			byte[] tag = (nameObject).getBytes();
			rtiAmb.updateAttributeValues(instanceHandle,attribHandleMap,tag,wrappedTimeForUpdate);
			System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": Inizialize "+istanceName+" Instance Attribute\n\n");
			
		}
		catch(Exception e){
			e.printStackTrace();
			
		}
		
	}
	
	public void updateObjectAttribute(String nameObject,String[] attributeValue,String istanceName,String[] attributeName){
		try{
			rawFederateTime = currentFederateTime.getTime();
			rawTimeForUpdate = rawFederateTime + federateLookAhead.getTime();
			wrappedTimeForUpdate = new DoubleTime(rawTimeForUpdate);
			
			/* Attributes mapping  and update */
			AttributeHandleValueMap attribHandleMap=(AttributeHandleValueMap)this.valueAttributeInstance.get(istanceName);
			
			int size=0;
			ObjectClassHandle handleObject = rtiAmb.getObjectClassHandle(nameObject);
			ObjectInstanceHandle instanceHandle=rtiAmb.getObjectInstanceHandle(istanceName);
			
			while(size<attributeValue.length){
				
				byte[] attribValueByte = attributeValue[size].getBytes();
				AttributeHandle attribHandle=rtiAmb.getAttributeHandle(handleObject, attributeName[size]);
				
				attribHandleMap.remove(attribHandle);
				attribHandleMap.put(attribHandle, attribValueByte);
				size++;
			}
			byte[] tag = (nameObject).getBytes();
			rtiAmb.updateAttributeValues(instanceHandle,attribHandleMap,tag,wrappedTimeForUpdate);
			
			System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": Update "+istanceName+" Instance Attribute");
			
		}
		catch(Exception e){
			e.printStackTrace();
			
		}
		
	}
	
	public void removeInstance(){
		Enumeration key=valueAttributeInstance.keys();
		try {
			while(key.hasMoreElements()){
				rtiAmb.deleteObjectInstance(rtiAmb.getObjectInstanceHandle((String)key.nextElement()), null);
			}
		} catch (DeletePrivilegeNotHeld e) {
			e.printStackTrace();
		} catch (ObjectInstanceNotKnown e) {
			e.printStackTrace();
		} catch (FederateNotExecutionMember e) {
			e.printStackTrace();
		} catch (SaveInProgress e) {
			e.printStackTrace();
		} catch (RestoreInProgress e) {
			e.printStackTrace();
		} catch (RTIinternalError e) {
			e.printStackTrace();
		}
		
	}
	
	public void subscribeObject(String name,String attribute){
		try{
			/* Ottiene l'handle per l'oggetto e l'attributo */
			/*handleSub = rtiAmb.getObjectClassHandle(name);
			System.out.println("\t"+currentFederateTime.getTime() + " " + fedName + ": ottiene l'handle per l'oggetto");
			attribHandleSub = rtiAmb.getAttributeHandle(handleSub, attribute);
			attribHandleSetSub = rtiAmb.getAttributeHandleSetFactory().create();
			attribHandleSetSub.add(attribHandleSub);
			//Sottoscrive 
			rtiAmb.subscribeObjectClassAttributes(handleSub, attribHandleSetSub);
			System.out.println("\t"+currentFederateTime.getTime() + " " + fedName + ": sottoscrive l'attributo dell'oggetto");
			*/
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void resignFederation(){
		try{
			rtiAmb.resignFederationExecution(ResignAction.NO_ACTION);
			System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": resigns federation");
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/*********************************************End RTI services*********************************************/
		

	/*********************Federate's services of own ambassador**********************/
	@Override
	public void discoverObjectInstance(ObjectInstanceHandle objectInstanceHandle, 
										ObjectClassHandle objectClassHandle, 
										String objectName){
		System.out.println("\t"+currentFederateTime.getTime() + " " + fedName + ": I found instance object " + objectName);
	}
	@Override
	public void timeConstrainedEnabled(LogicalTime theTime)
	{
	   System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": [FED AMB] Time constrained enabled!");
	   timeConstrainedEnabled = true;
	}
	   
	@Override
	public void timeRegulationEnabled(LogicalTime theTime)
	{
	   System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": [FED AMB] Time regulation enabled!");
	   timeRegulatingEnabled = true;
	}
	   
	@Override
	public void timeAdvanceGrant(LogicalTime theTime)
	{
		
			
		   currentFederateTime = (DoubleTime)theTime;
		   if(start.oStream!=null)
			try {
				String temp="Event Time Grant:"+currentFederateTime.getTime()+"\r\n\r\n";
				start.oStream.write(((temp).getBytes()));
			} catch (IOException e) {
				e.printStackTrace();
			}
	} 
	
		
	@Override
	public void receiveInteraction(InteractionClassHandle interactionClass, 
									ParameterHandleValueMap parameterValues, 
									byte[] userSuppliedTag, 
									OrderType orderType, 
									TransportationType transportationType){
			RequestToOmnet requestNt=null;
			RequestToOmnet requestBackTraffic=null;
			SendFailure sendFl=null;
			SendRecovery sendRc=null;
			
			String tag = new String(userSuppliedTag);
			System.out.println("Interaction received: " + tag);
			
			if(parameterValues.keySet().isEmpty()){
				System.out.println("\t" + currentFederateTime.getTime()+ " " + fedName + "Collection parameters empty");
			}
			else{
				
				if(tag.compareTo("RequestToOmnet")==0){
					requestNt=createRequestToOmnet(parameterValues,interactionClass);
				}
				else if(tag.compareTo("SendFailure")==0){
					sendFl=createSendFailure(parameterValues,interactionClass);
				}
				else if(tag.compareTo("SendRecovery")==0){
					sendRc=createSendRecovery(parameterValues,interactionClass);
				}
				else if(tag.compareTo("BackgroundTraffic")==0){
					requestBackTraffic=createBackgroundTraffic(parameterValues,interactionClass);
				}
				try {
						if(requestNt!=null){
				        	String temp=createRequestServer(requestNt);
				        	System.out.println("requestNt = " + requestNt + ", temp = " + temp);
				        	start.oStream.write(temp.getBytes());
				        }
				         else if (sendFl!=null){
				        	 String temp=createRequestServer(sendFl);
				        	start.oStream.write(temp.getBytes());
				        }
				         else if(sendRc!=null){
				         	String temp=createRequestServer(sendRc);
							start.oStream.write(temp.getBytes());
				        }
				         else if(requestBackTraffic!=null){
				        	String temp=createRequestServer(requestBackTraffic);
				        	System.out.println("requestBackTraffic:["+temp+"]");
				        	start.oStream.write(temp.getBytes());
				        }
									
				} catch (IOException e) {
						e.printStackTrace();
				}
			}
			if(userSuppliedTag != null){
				//System.out.println("\t" + currentFederateTime.getTime() + " " + "Tag: " + new String(userSuppliedTag));
			}
		}
	
	
	

	@Override
	public void announceSynchronizationPoint(String syncLabel, byte[] tag){
		/*
		if (syncLabel.equals("start")) {
			this.startSyncPointAnnounced = true;
		}
		else if (syncLabel.equals("end")) {
			this.endSyncPointAnnounced = true;
		}*/
		System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": Announce of synchronization points: " + syncLabel);
		
	}
	
	@Override
	public void federationSynchronized(String syncLabel){
		/* NEW VERSION
		if(syncLabel.equals("start"))
			this.startSyncPointAchieved = true;
		if(syncLabel.equals("end"))
			this.endSyncPointAchieved = true;
		System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": Reached synchronization point: " + currentFederateTime.getTime());
		*/
		if(syncLabel.equals("StartTest"))
			syncronizedStart=true;
		else if(syncLabel.equals("EndTest"))
			syncronizedEnd=true;
		System.out.println("\t" + currentFederateTime.getTime() + " " + fedName + ": Reached synchronization point: " + currentFederateTime.getTime());	
	}
	
	/*NEW VERSION
	public RTIambassador getRti() {
		return this.rtiAmb;
	}
	*/
	
	
		
}
